using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace FindItNow.UI
{
	public partial class FindForm : Form
	{
		private readonly List<FindRequest> _requests;
		private int _index;

		private const string FileTypesInactiveCaption = "File Types";
		private const string QueryInactiveCaption = "Find In Files";
		private const string LookInInactiveCaption = "Look In";

		public FindForm(string SearchTerm, List<FindRequest> requests, List<string> extensions)
		{
			_requests = requests;
			_index = requests.Count;

			InitializeComponent();

			foreach (string extension in extensions)
				_fileTypesCB.Items.Add("*" + extension);

			foreach (FindRequest request in _requests)
			{
				if (request.FileTypes.Trim().Length > 0 && !_fileTypesCB.Items.Contains(request.FileTypes))
					_fileTypesCB.Items.Add(request.FileTypes);

				if (request.LookIn != FilesSource.Custom)
					continue;

				if (_lookInCB.Items.Contains(request.LookInPath))
					continue;

				_lookInCB.Items.Add(request.LookInPath);
			}

			if (_requests.Count > 0)
				PopulateFromRequest(_requests[_requests.Count - 1]);

			_queryTextBox.Text = SearchTerm;

			UpdateTextBox(_queryTextBox, QueryInactiveCaption, true);
		}

		public FilesSource LookIn
		{
			set
			{
				int valueAsInt = (int)value;

				if (valueAsInt < 2)
				{
					_lookInCB.SelectedIndex = valueAsInt;
					UpdateComboBox(_lookInCB, LookInInactiveCaption, _lookInCB.Focused);
				}
			}
		}

		private void OnKeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Escape)
			{
				DialogResult = DialogResult.Cancel;
				Close();
			}

			if (e.KeyCode == Keys.Enter)
			{
				FindRequest request = CreateRequest();

				if (request.Query.Trim().Length == 0)
					DialogResult = DialogResult.Cancel;
				else
				{
					DialogResult = DialogResult.OK;
					_requests.Add(request);
				}
				
				Close();
			}

			if (_queryTextBox.Focused)
			{
				if (e.KeyCode == Keys.Down && _index < _requests.Count)
				{
					_index = Math.Min(_index + 1, _requests.Count - 1);

					PopulateFromRequest(_requests[_index]);
					e.Handled = true;
				}

				if (e.KeyCode == Keys.Up)
				{
					_index = Math.Max(_index - 1, 0);

					PopulateFromRequest(_requests[_index]);
					e.Handled = true;
				}
			}
		}

		private void PopulateFromRequest(FindRequest request)
		{
			_queryTextBox.Text = request.Query;
			_matchCaseCB.Checked = request.MatchCase;
			_wholeWordCB.Checked = request.WholeWord;
			_fileTypesCB.Text = request.FileTypes;

			if (request.LookIn == FilesSource.Custom)
				_lookInCB.SelectedIndex = _lookInCB.Items.IndexOf(request.LookInPath);
			else
				_lookInCB.SelectedIndex = (int)(request.LookIn);

			UpdateTextBox(_queryTextBox, QueryInactiveCaption, _queryTextBox.Focused);
			UpdateComboBox(_fileTypesCB, FileTypesInactiveCaption, _fileTypesCB.Focused);
			UpdateComboBox(_lookInCB, LookInInactiveCaption, _lookInCB.Focused);
		}

		private FindRequest CreateRequest()
		{
			bool customLookIn = (_lookInCB.SelectedIndex < 0 && _lookInCB.Text != LookInInactiveCaption) || _lookInCB.SelectedIndex >= 2;

			var request = new FindRequest
			{
			    Query = _queryTextBox.Text != QueryInactiveCaption ? _queryTextBox.Text : "",
			    MatchCase = _matchCaseCB.Checked,
			    WholeWord = _wholeWordCB.Checked,
			    FileTypes = _fileTypesCB.Text != FileTypesInactiveCaption ? _fileTypesCB.Text : "",
				LookIn = customLookIn ? FilesSource.Custom : (FilesSource)(Math.Max(0, _lookInCB.SelectedIndex)),
				LookInPath = customLookIn ? _lookInCB.Text : ""
			};

			if (_index < _requests.Count && RequestsMatch(request, _requests[_index]))
				_requests.Remove(_requests[_index]);

			return request;
		}

		private static bool RequestsMatch(FindRequest lhs, FindRequest rhs)
		{
			return lhs.Query == rhs.Query && 
				lhs.MatchCase == rhs.MatchCase && 
				lhs.WholeWord == rhs.WholeWord &&
			    lhs.DisplayAllMatches == rhs.DisplayAllMatches &&
				lhs.FileTypes == rhs.FileTypes &&
				lhs.LookIn == rhs.LookIn &&
				lhs.LookInPath == rhs.LookInPath;
		}

		private void OnEnterFileTypes(object sender, EventArgs e)
		{
			UpdateComboBox(_fileTypesCB, FileTypesInactiveCaption, true);
		}

		private void OnLeaveFileTypes(object sender, EventArgs e)
		{
			UpdateComboBox(_fileTypesCB, FileTypesInactiveCaption, false);
		}

		private void OnEnterQuery(object sender, EventArgs e)
		{
			UpdateTextBox(_queryTextBox, QueryInactiveCaption, true);
		}

		private void OnLeaveQuery(object sender, EventArgs e)
		{
			UpdateTextBox(_queryTextBox, QueryInactiveCaption, false);
		}

		private void OnEnterLookIn(object sender, EventArgs e)
		{
			UpdateComboBox(_lookInCB, LookInInactiveCaption, true);
		}

		private void OnLeaveLookIn(object sender, EventArgs e)
		{
			UpdateComboBox(_lookInCB, LookInInactiveCaption, false);
		}

		private static void UpdateTextBox(TextBox textBox, string inactiveCaption, bool focused)
		{
			if (focused)
			{
				textBox.ForeColor = SystemColors.ActiveCaptionText;

				if (textBox.Text == inactiveCaption)
					textBox.Text = "";
			}
			else
			{
				if (textBox.Text.Trim().Length == 0 || textBox.Text == inactiveCaption)
				{
					textBox.ForeColor = SystemColors.InactiveCaption;
					textBox.Text = inactiveCaption;
				}
				else
					textBox.ForeColor = SystemColors.ActiveCaptionText;
			}
		}

		private static void UpdateComboBox(ComboBox comboBox, string inactiveCaption, bool focused)
		{
			if (focused)
			{
				comboBox.ForeColor = SystemColors.ActiveCaptionText;

				if (comboBox.Text == inactiveCaption)
					comboBox.Text = "";
			}
			else
			{
				if (comboBox.Text.Trim().Length == 0 || comboBox.Text == inactiveCaption)
				{
					comboBox.ForeColor = SystemColors.InactiveCaption;
					comboBox.Text = inactiveCaption;
				}
				else
					comboBox.ForeColor = SystemColors.ActiveCaptionText;
			}
		}
	}
}